#include "SockStream.h"
#include "SockAcceptor.h"

#include <errno.h>
#include <stdio.h>
#include <sys/epoll.h>
#include <iostream>

int main ()
{
    InetAddr local_addr (9999);

    SockAcceptor acceptor;
    if (acceptor.open (local_addr) != 0)
    {
	std::cout << errno << std::endl;
	perror ("open");
	return 0;
    }
    NDK::set_non_block_mode (acceptor.handle ());
    int ep_fd = epoll_create (1000);
    struct epoll_event ep, evs[1000];
    ep.events  = EPOLLIN | EPOLLET;
    ep.data.fd = acceptor.handle ();
    epoll_ctl (ep_fd, EPOLL_CTL_ADD, acceptor.handle (), &ep);
    int close_count = 0;
    int connection_count = 0;
    char buff[4096] = {0};
    while (1)
    {
	int ret = epoll_wait (ep_fd, evs, 1000, -1);
	if (ret > 0)
	{
	    for (int i = 0; i < ret; ++i)
	    {
		if (evs[i].data.fd == acceptor.handle ())
		{
		    NDK_HANDLE new_handle = ::accept (evs[i].data.fd,
			    0,
			    0);
		    if (new_handle != -1)
		    {
			++connection_count;
			fprintf (stderr, "new connection index = %d, fd = %d\n", 
				connection_count,
				new_handle);
			NDK::set_non_block_mode (new_handle);
			struct epoll_event eh;
			eh.events  = EPOLLIN | EPOLLET;
			eh.data.fd = new_handle;
			epoll_ctl (ep_fd, EPOLL_CTL_ADD, eh.data.fd, &eh);
		    }
		}else
		{
		   int ret = 0;
		   while (1)
		   {
		       ret = NDK::recv (evs[i].data.fd, buff, sizeof (buff), 0);
#if 0  // for test
		       if (ret > 0 && ret < sizeof (buff))
			       break;
#endif
		       if (ret == -1 && errno == EAGAIN)
			   break;
		       else if (ret == -1 && errno != EAGAIN)
		       {
			   fprintf (stderr, "peer recv error = %d\n", errno);
			   NDK::closesocket (evs[i].data.fd);
			   break;
		       }else if (ret == 0)
			   break;
		       //else
		       //fprintf (stderr, "peer recv ret = %d\n", ret);
		   }
		   if (ret == 0)
		   {
		       ++close_count;
		       fprintf (stderr, "peer close index = %d, fd = %d\n", 
			       close_count,
			       evs[i].data.fd);
		       NDK::closesocket (evs[i].data.fd);
		       struct epoll_event eh;
		       eh.events  = EPOLLIN | EPOLLET;
		       eh.data.fd = evs[i].data.fd;
		       epoll_ctl (ep_fd, EPOLL_CTL_DEL, eh.data.fd, &eh);
		   }
		}
	    }
	}
    }
    NDK::closesocket (acceptor.handle ());
    return 0;
}
